home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 007 / c_lib01.arc / LS.C < prev    next >
Text File  |  1985-10-16  |  16KB  |  524 lines

  1. /*
  2. NAME
  3.     dirc    -   UNIX-"ls" like directory listing utility written in 'C'.
  4.             Tested under PC-DOS using Lattice C rel 2.11.
  5.             This version allows limited recursive directory searches.
  6.  
  7. AUTHOR
  8.     Marty Ross,    Computing Resource Center,    Santa Monica, Ca.
  9.  
  10.     For updates and more utilities of the like, call CRC-PC, or CRCBBS
  11.     bulletin board system(s).  Currently at:
  12.  
  13.     (213) 829-1487    (300 baud, IBM-PC)
  14.     (213) 828-1331  (300 baud, VM/370) <-- type "LOG DEMO DEMO" for access
  15.  
  16.     NOTE: We are moving around late OCT., 1984 so above numbers will be
  17.           invalid after OCT, 1984.
  18.  
  19. SYNOPSIS 
  20.    [pc/ms-dos]
  21.     A>dirc    [-options] [d:][/path/]filename[.ext] 
  22.     
  23.    [as C function]
  24.     ret =   dirc(s,op);
  25.         char *s;    /* Pointer to [d:][/path/]filename[.ext] */
  26.         char *op;    /* Pointer to option string */
  27.                 /* Will 'ret' urn 0 normally, or 2 if no find */
  28. where:    
  29.     options     
  30.           Is a string of lower case letters selecting
  31.         how many columns to generate, which files, according to
  32.         file attribute, should be displayed, and the selection
  33.         of file size/date of last access, volume header display,
  34.         subdirectory/time of creation, and file attribute bit
  35.         display.  The option string "shrvdzt1" for instance,
  36.         will generate one column (1), will display system files
  37.         (s), hidden files (h), read-only files (r), volume-header
  38.         entry [files] (v), subdirectories (d), siZe (z), and
  39.         date-Time (t) information when it outputs its list.
  40.         An added feature in this version is the 'e' option, which
  41.         will also enable the 'd' option to show subdirectories
  42.         (which match the filename - usually '*.*'), and invoke
  43.         itself recursively for that subdirectory.  Thus, an entire
  44.         hard-disk or other tree-structured file system can be
  45.         completely scanned with one command.
  46.  
  47.         Note that because of DOS interfacing conventions, only
  48.         directories which match the file specification you typed
  49.         on the command line (if none, '*.*') will be shown.  This 
  50.         disables a potentially very useful feature: ability to 
  51.         selectively scan across directories for particular files.  
  52.         I will most likely include that feature in the next release
  53.         of DIRC, when I invent my own subroutines to handle wildcard
  54.         symbols myself - i'll always ask DOS for *.* and do the
  55.         filtering myself!
  56.  
  57.  
  58.     option letter        meaning
  59.     -------------
  60.         
  61.         1        Generate one column/line output.
  62.         2        Generate two columns/line output.
  63.         3        Generate three columns/line output.
  64.         4        Generate four colums/line output.
  65.  
  66.         a        Archive bit.  Set on when file written    
  67.                 to since last FDISK backup.  Allows DIRC to
  68.                 select only files changed since last backup.
  69.         
  70.         b        Bits.  Causes file access (mode) bits to be 
  71.                 displayed before each filename.
  72.  
  73.         d        Directories.  Includes Subdirectories 
  74.                 in file searches.
  75.         
  76.         e        Expand.  Expand sub-directories which match
  77.                 given filename wildcard.  Should use "*.*"
  78.                 to get all subdirectories. 
  79.     
  80.         h        Hidden files. List files with 'hidden' status.
  81.     
  82.         l        Long.  Include '.' and '..' subdir files.
  83.  
  84.         q        Quiet.  Don't say "[/path/]filesp:" before dir.
  85.  
  86.         r        Read-Only bit. Files which cannot be written to.
  87.  
  88.         s        System file. Don't erase these files.
  89.  
  90.         t        Time & Date.  Include for each file.
  91.         
  92.         u        Un-archive bit.  See files which have not been
  93.                 changed since last FDISK BACKUP.
  94.  
  95.         v        Volume header(s?)
  96.  
  97.         x        Exclusive.  Don't list "normal" files.
  98.  
  99.         z        siZe.  Include for each file.
  100.  
  101.         ]        Right Justify filenames in filename field.
  102.  
  103.         [        Left Justfy filenames.
  104.  
  105.     ----------------
  106.  
  107.  
  108. DESCRIPTION
  109.  
  110.     DIRC provides a flexible directory interface to the PC-DOS
  111. file system when using C under the Lattice compiler.  Output goes
  112. to STDOUT, and for this test version written as a PC-DOS command,
  113. input is via the first two 'argv[]' tokens.  Since it is a demonstration
  114. of the capabilities of the DIRC function only, a simple option passing scheme
  115. (using the second token), was chosen rather than the more standard
  116. UNIX option scheme, where the option comes (optionally) first.
  117.  
  118.  
  119.     DIRC was written for PC-DOS using the Lattice C compiler.  The
  120. author claims to be no UNIX expert, but realizes that most of the features
  121. of the program are 'boarrowed' from that system.  The desired goal was a
  122. flexible way to provide directories from within C programs.  The first
  123. result of that effort lies herein, in a test 'shell' which calls DIRC
  124. using 'argv[1]' and 'argv[2]'.
  125.  
  126.     From PC-DOS, you can specify both file specification and option
  127. string as 'tokens', separating with a space.  Because DIRC options are
  128. lower case only (in the UNIX tradition), YOU MUST SPECIFY ALL OPTIONS 
  129. IN LOWER CASE!  
  130.  
  131.     Note that stack size is set large in case of deeply nested directories
  132. when recursive option 'e' is used.  If '*** STACK OVERFLOW ***' error STILL
  133. occurs, then you may override the stack size, using the Lattice Compiler, by
  134. typing an equal sign, followed by the desired stack size, in decimal.  
  135.  
  136. I.E.:
  137.  
  138. A>dirc =30000 *.*
  139. */
  140.  
  141. int    _stack    =    25000;        /* large stack in case of recursion! */
  142.  
  143. /* Following imitations of key routines in SEDIT.H */
  144. int newline()
  145. {
  146. printf("\n");
  147. return 0;
  148. }
  149.  
  150. spout(line,arg1,arg2)
  151. char *line;
  152. int arg1, arg2;
  153. {
  154. printf("%s",line);
  155. }
  156.  
  157. /* Start of DIRC.C */
  158. #include    <dos.h>        /* Note: Tested under Lattice Rel 2.11 */
  159. #define        BLANK        " "    /* For SPOUT */
  160. #define        DEF_OPTS    ""    /* Use internal defaults now */
  161. #define        DEF_FN        "*.*"
  162.  
  163. main(argc,argv)
  164. int argc;
  165. char *argv[];
  166. {
  167. int i, rc;
  168. char *opts, *fn;
  169.  
  170. if (argc<2) {
  171.     opts = DEF_OPTS;
  172.     fn = DEF_FN;
  173.     }
  174. else if (argv[1][0]=='-') {
  175.     if (argc<3) fn = DEF_FN;
  176.     else fn = argv[2];
  177.     opts = argv[1];    /* If options */
  178.     }
  179. else {
  180.     opts = DEF_OPTS;
  181.     fn = argv[1];
  182.     }
  183. rc=dirc(fn,opts);
  184. if (rc && rc!=2) printf("R(%d);\n",rc);
  185. }
  186.  
  187.  
  188. #define        FIND_FILE    0x4E        /* DOS find file command */
  189. #define        NEXT_FILE    0x4F        /* DOS next file command */
  190. #define        NORMAL_ATTR    0x20        /* "NORMAL" file attr */
  191. #define        DTA_SIZE    128        /* Size of DOS DTA */
  192. #define        B_F_WIDTH    13        /* 'vanilla' field width */
  193. #define        B_DIR_TYP    0        /* Default 'type' for DIR */
  194. #define        B_DIR_OPT    0x0B        /* File and size only dflt */
  195. #define        K        1024        /* What is a 'K' ? */
  196. #define        NA        0        /* No Argument - don't care */
  197. #define        SET_DTA        0x1A        /* Set DTA address DOS SVC */
  198.  
  199. char *filedate(), *filetime();            /* Forward references */
  200.  
  201.         /* Our attribute byte fields */
  202. #define        F_RONLY        1        /* Read only bit */
  203. #define     F_HIDDEN    2        /* File hidden */
  204. #define        F_SYSTEM    4        /* System file */
  205. #define        F_VOLUME    8        /* Volume */
  206. #define        F_SUBDIR    16        /* Subdirectory */
  207. #define        F_ARCHIVE    32        /* Archived */
  208. #define        F_B6        64
  209. #define        F_B7        128
  210.  
  211. char    fatbits[]    = "rhsvda!?";        /* Meaning of attribute bits */
  212.  
  213.         /* Our option bit flags image */
  214. #define        O_WIDTH        3        /* Two bit width field */
  215. #define        O_NONORMAL    4        /* Don't show normal files */
  216. #define        O_ONLYARCH    8        /* Only show archived files */
  217. #define        O_NOARCH    16        /* Only show non archived fls */
  218. #define        O_DATE        32        /* Include date/time */
  219. #define        O_SIZE        64        /* Show size of file */
  220. #define        O_ATTRIBS    128        /* Show file attribute bits */
  221. #define        O_QUIET        256        /* Quiet flag */
  222. #define        O_EXPAND    512        /* Expand sub-dirs */
  223. #define        O_RJUST        1024        /* Right- justify */
  224. #define        O_LONG        2048        /* Include '.' and '..' */
  225.     
  226. #define        COLON        ':'
  227. #define        ESCSYM        '\\'
  228. #define        ESCSTR        "\\"
  229.  
  230.  
  231.     /* k l u d g e macro (sorry) */
  232.                 /* on if attrib selected */
  233. #define      L_Field    (((options&O_ATTRIBS)?9:0)+f_width)   
  234.  
  235. int mdirfile(fn,type,options) 
  236. char *fn;
  237. char type;
  238. unsigned options;
  239. {
  240. int nff;
  241. int i, cp, rc;
  242. int r_col, f_width;
  243. char entr[81];                    /* maximum length output tok */
  244. char spbuf[10];
  245. char temp[40];
  246. char extbfr[128];            /* For rcrsv subdir expansion */
  247. unsigned ds,dx, es, bx;
  248. int dat,siz,attrs,rjust;
  249. union {                    /* DTA and DIR field image */
  250.     char    disk_buffer[DTA_SIZE];
  251.     struct    {
  252.             char      sys_data[21];
  253.             char      file_attribute;
  254.             unsigned file_time ;
  255.             unsigned file_date ;
  256.             long     file_size ;
  257.             char     fn_ext[13] ;
  258.             }  file_table;
  259.     } my_dta;
  260.  
  261. static int lvl;      /* Level of recursion - will be zero when prog begins */
  262.  
  263. lvl++;                        /* First level */
  264. rc = 1001;                    /* RC for no string given */
  265. if (*fn != '\0') {
  266.     nff = 0;                /* Zero files found so far */
  267.     f_width = B_F_WIDTH;            /* Fieldsize for plain dir */
  268.     dat = (options & O_DATE);
  269.     siz = (options & O_SIZE);        /* Size flag selected */
  270.     attrs = (options & O_ATTRIBS);        /* Attributes required ? */
  271.  
  272.     if (siz) f_width += 7;    /* adjust 'per field' size */
  273.     if (dat) f_width += 16;    /* etc...*/
  274.  
  275.     r_col = ((options & O_WIDTH)+1)*L_Field;
  276.     rjust = (options & O_RJUST);
  277.     getdta(&ds,&dx);        /* Get and save current DTA */
  278.     setdta(0,&my_dta);        /* Set up our own DTA */
  279.     rc = bdos2(FIND_FILE,NA,NA,type,fn);
  280.     if (rc==0) {        /* Look for ALL files */
  281.         while (rc==0) {
  282.             for (cp=0;cp<r_col&&rc==0;rc=bdos2(NEXT_FILE)) {
  283.                 if (!(options&O_LONG)) {
  284.                     if (!strcmp(my_dta.file_table.fn_ext,".") ||
  285.                         !strcmp(my_dta.file_table.fn_ext,".."))
  286.                         continue;
  287.                     }
  288.                 if (options&O_NONORMAL) {   /* -x */
  289.                     if (my_dta.file_table.file_attribute==NORMAL_ATTR)
  290.                         continue;
  291.                     }
  292.                 if (options&O_ONLYARCH) {   /* -a */
  293.                     if (!(my_dta.file_table.file_attribute&F_ARCHIVE)) 
  294.                         continue;
  295.                     }
  296.                 if (options&O_NOARCH) {     /* -u */
  297.                     if (my_dta.file_table.file_attribute&F_ARCHIVE) 
  298.                         continue;
  299.                     }
  300.                 if (nff++==0 && (options&O_QUIET)==0) {
  301.                     sprintf(temp,"%s;\n",fn);
  302.                     spout(temp,2,1);
  303.                     }
  304.                 if (attrs) {    /* -b */
  305.                     for (i=7;i>=0;i--) {
  306.                         if (my_dta.file_table.file_attribute&(1<<i)) {
  307.                             stccpy(spbuf,fatbits+i,2);
  308.                             spout(spbuf,2,1);
  309.                             }
  310.                         else spout("-",2,1);
  311.                         }
  312.                     spout(BLANK,2,1);
  313.                     }
  314.                 if (rjust) sprintf(entr,"%12s",my_dta.file_table.fn_ext);
  315.                 else sprintf(entr,"%-12s",my_dta.file_table.fn_ext);
  316.                 if (siz) {        /* -z */
  317.                     if (my_dta.file_table.file_attribute &
  318.                         F_VOLUME) sprintf(temp,"  <vol>");
  319.                     else if (my_dta.file_table.file_attribute &
  320.                         F_SUBDIR) sprintf(temp,"  <dir>");
  321.                     else sprintf(temp,"%6.1fK", 
  322.                        (((float)my_dta.file_table.file_size / (float)K) + (float)0.05) );
  323.                     strcat(entr,temp);
  324.                     }
  325.                 if (dat) {     /* -t */
  326.                     sprintf(temp,"  %s %s",
  327.                         filedate(my_dta.file_table.file_date),
  328.                         filetime(my_dta.file_table.file_time));
  329.                     strcat(entr,temp);
  330.                     }
  331.                 i = f_width - strlen(entr) - 1;
  332.                 while(i-->0) spout(BLANK,2,1);
  333.                 spout(entr,2,1);
  334.                 if ((my_dta.file_table.file_attribute&F_SUBDIR) && (options&O_EXPAND) 
  335.                      && strcmp(my_dta.file_table.fn_ext,"..")
  336.                      && strcmp(my_dta.file_table.fn_ext,".")) {
  337.                     spout("\n",2,1);
  338.                     mknwdir(extbfr,fn,my_dta.file_table.fn_ext);
  339.                     rc = mdirfile(extbfr,type,options);
  340.                     cp = 0;
  341.                     if (rc==1) break;
  342.                     }
  343.                 else {
  344.                     cp+=L_Field;    /* Account for horiz motion */
  345.                     if (cp<r_col) {
  346.                         spout(BLANK,2,1);
  347.                         if (attrs || dat) spout(BLANK,2,1);
  348.                         }
  349.                     else if (newline()) {
  350.                         rc=1;
  351.                         break;
  352.                         }
  353.                     }
  354.                 }    /* End FOR */
  355.             if (rc==1) break;
  356.             }     /* End WHILE */
  357.         }    /* End IF */
  358.     setdta(ds,dx);            /* Restore callers' DTA */
  359.     } /* endif */
  360.  
  361. if (nff==0) {
  362.     if (lvl==1) spout("No file(s) found.\n",2,1); /* 1st level only */
  363.     else {
  364.         if (!(options&O_NONORMAL)) {
  365.             sprintf(extbfr,"No files: %s\n",fn);
  366.             spout(extbfr,2,1);
  367.             }
  368.         }
  369.     rc = 2;            /* No files found */
  370.     }
  371. else {
  372.     if (rc==18) rc=0;    /* Get rid of error 18 if files found */
  373.     if (cp && cp<r_col) spout("\n",2,1);
  374.     if (lvl!=1) {
  375.         sprintf(extbfr,"(End of %s)\n",fn);
  376.         spout(extbfr,2,1);
  377.         }
  378.     }
  379. return rc;
  380. }  /* enddir */
  381.  
  382. int dirc(fn,optlist)
  383. char *fn;
  384. char *optlist;
  385. {
  386. unsigned opts;        /* directory listing option bits */
  387. char type;        /* File attribute */
  388.  
  389. type = 0;        /* Normal files only */
  390. opts = 0;        /* Default one column */
  391.             /* Default size & date/time */
  392. /* if (!*optlist) opts = opts | O_SIZE | O_DATE;  */  
  393.  
  394. for (;*optlist;optlist++) {
  395.     switch(*optlist) {
  396.         case '-': ;            /* Freedom of option passing */
  397.     break;    case 'v': type = type | F_VOLUME;    /* Volume headers req'd */
  398.         break;    case 'r': type = type | F_RONLY;    /* Read-only files */
  399.         break;    case 'h': type = type | F_HIDDEN;    /* Hidden files */
  400.     break;     case 'd': type = type | F_SUBDIR;    /* SubDirectories */
  401.     break;    case 's': type = type | F_SYSTEM;    /* System files */
  402.     break;    case '!': type = type | F_B6;        /* B6 ?? */
  403.     break;    case '@': type = type | F_B7;        /* B7 ?? */
  404.     break;    case 'x': opts = opts | O_NONORMAL;    /* Exclusive */
  405.     break;    case 'a': opts = opts | O_ONLYARCH;    /* Archived only */
  406.               type = type | F_ARCHIVE;    /* Search for it, too */
  407.     break;    case 'u': opts = opts | O_NOARCH;    /* Un archived only */
  408.               type = ((~F_ARCHIVE)&type);    /* Un-do the archive bit */
  409.     break;    case 't': opts = opts | O_DATE;        /* Show date/time */
  410.     break;    case 'z': opts = opts | O_SIZE;        /* Show size */
  411.     break;    case 'b': opts = opts | O_ATTRIBS;    /* Show attrib bits */
  412.     break;    case 'q': opts = opts | O_QUIET;    /* Shut up */
  413.     break;    case 'e': opts = opts | O_EXPAND;     /* Expand subdirs */
  414.               type = type | F_SUBDIR;
  415.     break;    case 'l': opts = opts | O_LONG;        /* Incl. '.' and '..' */
  416.     break;    case ']': opts = opts | O_RJUST;    /* Right justify fn's */
  417.     break;    case '[': opts = opts & ~O_RJUST;    /* Turn off RJUST */
  418.     break;    case '1': ;                               /* number of columns */
  419.             case '2': ;
  420.             case '3': ;
  421.             case '4': opts = (opts&~(unsigned)3) | ((*optlist)-'1');
  422.     break;  default: {
  423.             spout("Bad internal dir opts\n",2,1);
  424.             return 1;
  425.             }
  426.         }
  427.     }
  428. if (*fn=='\0') fn="*.*";        /* Default for current version */
  429. return (mdirfile(fn,type,opts));
  430. }
  431.  
  432. mknwdir(buffer,curspec,newdir)
  433. char buffer[], curspec[], newdir[];
  434. {
  435. char mybuf[32];
  436. int i;
  437.  
  438. split_file(curspec,buffer,mybuf);
  439. i = strlen(buffer);
  440. if (i) {
  441.     if (buffer[--i]!=ESCSYM && buffer[i]!=COLON) strcat(buffer,ESCSTR);
  442.     }    
  443. strcat(buffer,newdir);
  444. strcat(buffer,ESCSTR);
  445. strcat(buffer,mybuf);
  446. }
  447.  
  448. split_file(curspec,buffer,hisbuf)
  449. char *curspec, *buffer, *hisbuf;
  450. {
  451. int i;
  452.  
  453. buffer[0] = hisbuf[0] = '\0';
  454. i = strlen(curspec);
  455. if (i) {
  456.     while(curspec[--i]!=ESCSYM && curspec[i]!=COLON && i!=0);
  457.     if (i) stccpy(buffer,curspec,++i+1);
  458.     strcpy(hisbuf,curspec+i);
  459.     }
  460. }
  461.  
  462. char *filetime(codetime)
  463. unsigned codetime;
  464. {
  465. static char ftime[7];
  466. sprintf(ftime,"%02d:%02d",(codetime&0xF800)>>11,
  467.               (codetime&0x07E0)>>5);
  468. return(ftime);
  469. }
  470.  
  471. char *filedate(codedate)
  472. unsigned codedate;
  473. {
  474. static char fdate[11];    
  475.  
  476. sprintf(fdate,"%02d/%02d/%02d",
  477.     (codedate&0x01E0)>>5,
  478.     (codedate&0x001F),
  479.     ((codedate&0xFE00)>>9)+80);
  480. return(fdate);
  481. }
  482.  
  483. #define        GETDTA    0x2F
  484. #define        SETDTA    0x1A
  485.  
  486. /* (8)    register = mdos(ah,al,bx,cx,dx)    * Call DOS function (ah), pass parms */
  487. bdos2(ah,al,bx,cx,dx)
  488. char ah,al;
  489. int bx,cx,dx;
  490. {
  491. union         REGS     myregs;
  492. myregs.h.ah = ah;
  493. myregs.h.al = al;
  494. myregs.x.bx = bx;
  495. myregs.x.cx = cx;
  496. myregs.x.dx = dx;
  497. intdos(&myregs,&myregs);
  498. return myregs.x.ax;
  499. }
  500.  
  501. getdta(esptr,bxptr)
  502. unsigned *esptr,*bxptr;
  503. {
  504. union         REGS     myregs;
  505. struct         SREGS    mysregs;
  506. segread(&mysregs);        /* Lattice suggests reading seg regs first */
  507. myregs.h.ah = GETDTA;
  508. intdosx(&myregs,&myregs,&mysregs);
  509. *esptr = mysregs.es;        /* Get DTA outputs to ES:BX */
  510. *bxptr = myregs.x.bx;
  511. }
  512.  
  513. setdta(es,bx)
  514. unsigned es,bx;
  515. {
  516. union         REGS     myregs;
  517. struct         SREGS    mysregs;
  518. segread(&mysregs);        /* Lattice suggests reading seg regs first */
  519. myregs.h.ah = SETDTA;        /* Assign new DTA function code */
  520. myregs.x.dx = bx;        /* Assign new offset to DTA */
  521. if (es!=0) mysregs.ds = es;        /* If zero, use our data segment */
  522. intdosx(&myregs,&myregs,&mysregs);     /* Set DTA req's DS:DX as argument */
  523. }
  524.